package com.htfyun.hardware.leds;

import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

public enum BreatheLedController {

    INSTANCE,
    ;

    private static final String TAG = "LedController";

    private static final boolean kernel_debug = false;


    BreatheLedController() {

        if (initBreatheLedType(BreatheLedType.left)) {
            Log.e(TAG, "LedController initBreatheLedType left ok.");
        }
        if (initBreatheLedType(BreatheLedType.right)) {
            Log.e(TAG, "LedController initBreatheLedType right ok.");
        }
    }

    /**
     * 通过初始化呼吸灯来获取必要的信息.
     * @param type {@link BreatheLedType}
     * @return
     */
    private boolean initBreatheLedType(BreatheLedType type) {
        String path = type.getPathOfConfig();

        List<String> stringList = readFileContent(path);

        if (stringList == null || stringList.size() != 1) {
            return false;
        }

        //the string is: level,max_brightness,min_brightness,step,ledNum
        String configString = stringList.get(0);
        Log.d(TAG, "BLN " + type.getName() + " config:" + configString);

        if (TextUtils.isEmpty(configString)) {
            return false;
        }

        String items[] = configString.split(",");
        if (items.length < 5) {
            Log.e(TAG, "Invalid Bln Config:" + configString);
            return false;
        }

        try {
            type.setBrightnessLevel(Integer.parseInt(items[0]));
            type.setMaxBrightness(255);
            type.setLimitBrightness(Integer.parseInt(items[1]));//tanlq add
            type.setMinBrightness(Integer.parseInt(items[2]));
            type.setStepBrightness(Integer.parseInt(items[3]));
            type.setLedNumbers(Integer.parseInt(items[4]));

            Log.d(TAG, "initBreatheLedType: " + type);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }

    //////////////////////////////////////////////////////////

    public void setAllLedLight(boolean on, BreatheLedType... types) {

        if (types == null || types.length == 0) {
            return;
        }

        for (BreatheLedType type : types) {
            int brightness = 0;
            if (on) {
                brightness = getMaxLedBrightness(type);
            }

            for (int i = 0; i < type.getLedNumbers(); i++) {
                setLedLight(type, i, brightness);
            }
        }

    }
    public void setLedLight(BreatheLedType type, int ledId, int brightness) {

        setLedLight(type, ledId, brightness, 0);

    }
    /**
     *
     * @param type {@link BreatheLedType}
     * @param ledId 0~{@link BreatheLedType#getLedNumbers() - 1}
     * @param brightness 0~{@link BreatheLedType#getMaxBrightness()}, 0 means off
     * @param onTime the time keep on, if onTime is 0, the led will keep on util set again
     */
    public void setLedLight(BreatheLedType type, int ledId, int brightness, long onTime) {

        if (ledId >= type.getLedNumbers() || ledId < 0) {
            Log.e(TAG,  "BreatheLedType name = " + type.getName() + ", Invalid LedNum=" + ledId + ", maxLedNums=" + type.getLedNumbers());
            return;
        }

        String cmd = "" + ledId + "," + brightness + "," + onTime;
        writeFileContent(type.getPathOfLight(), cmd);

    }

    public int getLedNumbers(BreatheLedType type) {
        return type.getLedNumbers();
    }

    public int getMaxLedBrightness(BreatheLedType type){
        return type.getLimitBrightness();
    }

    public int getMinLedBrightness(BreatheLedType type) {
        return type.getMinBrightness();
    }

    /**
     * 获取某个led number的亮度
     * @param type {@link BreatheLedType}
     * @param ledId 0~{@link BreatheLedType#getLedNumbers() - 1}
     * @return
     */
    public int getLightOfLedNumber(BreatheLedType type, int ledId) {

        if (ledId >= type.getLedNumbers() || ledId < 0) {
            Log.e(TAG,  "BreatheLedType name = " + type.getName() + ", Invalid LedNum=" + ledId + ", maxLedNums=" + type.getLedNumbers());
            return -1;
        }

        List<String> ledLightsList = readFileContent(type.getPathOfLight());
        if (ledLightsList.size() == 1) {
            String ledLights = ledLightsList.get(0);
            String items[] = ledLights.split(",");
            if (items.length > ledId) {
                try {
                    return Integer.parseInt(items[ledId]);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return -1;
    }

    /**
     * @param animationAttr 动画id, 当为{@link BreatheLedAnimationAttr#stop}时, #intervalBetweenAnimationFrame 和 #marqueeCount 无用
     * @param intervalBetweenAnimationFrame_ms 动画每帧变化之间的时长，可以控制动画的速度
     * @param marqueeCount  只对 {@link BreatheLedAnimationAttr#marquee_with_count} 有效，表示跑马灯转动的圈数。
     * @param types  {@link BreatheLedType}
     */

    public void startAnimation(BreatheLedAnimationAttr animationAttr, long intervalBetweenAnimationFrame_ms, int marqueeCount, BreatheLedType... types) {
        if (types == null || types.length == 0) {
            return;
        }

        String config = "" + animationAttr.getAnimationID() + "," + intervalBetweenAnimationFrame_ms + "," + marqueeCount;

        for (BreatheLedType type : types) {
            writeFileContent(type.getPathOfModel(), config);
        }
    }

    /**
     * 停止动画
     * @param types {@link BreatheLedType}
     */
    public void stopAnimation(BreatheLedType... types) {
        Log.d(TAG, "stopAnimation!!");
        startAnimation(BreatheLedAnimationAttr.stop, 0, 0, types);
    }

    /**
     * 批量操作led
     * @param batchOperationInfoList
     * @param types {@link BreatheLedType}
     */
    public void setLedLightInBatchOperation(List<BreatheLedBatchOperationInfo> batchOperationInfoList,
                                            BreatheLedType... types) {

        if (batchOperationInfoList == null || batchOperationInfoList.isEmpty()) {
            return;
        }
        if (types == null || types.length == 0) {
            return;
        }

        for (BreatheLedType type : types) {
            int ledCount = Math.min(getLedNumbers(type), batchOperationInfoList.size());
            StringBuilder configStringBuilder = new StringBuilder("@" + ledCount);
            for (int i = 0; i < ledCount; i++) {
                BreatheLedBatchOperationInfo info = batchOperationInfoList.get(i);
                configStringBuilder.append(",");
                configStringBuilder.append(info.getLedId());
                configStringBuilder.append(",");
                configStringBuilder.append(info.getBrightLess());
                configStringBuilder.append(",");
                configStringBuilder.append(info.getOnTime());
            }
            writeFileContent(type.getPathOfLight(), configStringBuilder.toString());

        }

    }

    /**
     * 特殊用法, 来配置内核的led
     * @param level
     * @param maxBrightness
     * @param minBrightness
     * @param stepBrightness
     * @param types
     */

    public void kernelConfigLed(int level, int maxBrightness, int minBrightness, int stepBrightness, BreatheLedType... types) {
        Log.d(TAG, "configLed:level=" + level + ",maxBrightness=" + maxBrightness + ",stepBrightness=" + stepBrightness);
        String config = "" + level + "," + maxBrightness + "," + minBrightness + "," + stepBrightness;
        if (types == null || types.length == 0) {
            return;
        }
        if(kernel_debug){

            for (BreatheLedType type : types) {
                writeFileContent(type.getPathOfConfig(), config);
                initBreatheLedType(type);
            }
        }
    }

    /**
     * 设置呼吸灯是否在设备进入休眠时, 关闭该呼吸灯.
     * @param off true: 进入休眠是关闭, false: 进入休眠时, 不关闭
     * @param types
     */
    public void setLedOffInSuspend(boolean off, BreatheLedType... types) {

        if (types == null || types.length == 0) {
            return;
        }
        for (BreatheLedType type : types) {
            setLedOffInSuspend(off, type.getPathOfOffLedInSuspend());

        }

    }

    public boolean isLedOffInSuspend(BreatheLedType type) {
        return isLedOffInSuspend(type.getPathOfOffLedInSuspend());

    }

    /**
     * pudding_plus:/sys/class/bln-left # cat off_led_in_suspend
     * 1
     * @param path
     * @return
     */
    private boolean isLedOffInSuspend(String path) {

        List<String> contents = readFileContent(path);
        if (contents == null || contents.isEmpty()) {
            return false;
        }

        String cmd = contents.get(0);

        return cmd.contains("1");

    }

    /////////////////////////////////////////////////////////

    /**
     * 设置灯, 在进入suspend的时候就关闭.
     * @param off true: 进入suspend的时候, 就关闭; false: 保留现有状态
     */
    private void setLedOffInSuspend(boolean off, String path) {

        String cmd = (off ? "1" : "0");
        writeFileContent(path, cmd);

    }

    /////////////////////////////////////////////////////////
    /*
     * 以行为单位读取文件，常用于读面向行的格式化文件
     * @param fileName 文件名
     */
    private synchronized List<String> readFileContent(String fileName) {
        File file = new File(fileName);
        BufferedReader reader = null;
        List<String> stringList = new ArrayList<String>();
        try {
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                stringList.add(tempString.replace(" ", "").replaceAll("\r|\n*", ""));
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }
        return stringList;
    }

    private synchronized void writeFileContent(String fileName, String content) {
        File file = new File(fileName);
        Writer writer = null;
        try {
            writer = new OutputStreamWriter(new FileOutputStream(file));
            writer.write(content);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e1) {
                }
            }
        }
    }

}
